<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>函数</title>
</head>
<body>
    <script>
        "use strict";
        /*
            函数对任何语言而言都是一个核心的概念，通过函数可以封装任意多条语句，而且可以在任何地方，任何时候调用执行。ECMAScript中的函数
            使用function关键字来声明，后跟一组参数以及函数体。函数的基本语法如下所示：
                function functionName(arg0, arg1, age2 ... argN) {
                    statements;
                }
            以下是一个函数示例：
                function sayHi(name, message) {
                    console.log("Hello " + name + ", " + message);
                }

            这个函数可以通过其函数名来调用，后面还要加上一对圆括号和参数（圆括号中的参数如果有多个，可以用逗号隔开）。调用sayHi()函数的代码
            如下所示：
                sayHi("Nicholas", "How old are you today?");

            ECMAScript中的函数在定义时不必指定是否返回值。实际上，任何函数在任何时候都可以通过return语句后跟要返回的值来实现返回值。
            示例：
                function sum(num1, num2) {
                    return num1 + num2;
                }
            
            这个sum()函数的作用就是把两个值加起来返回一个结果，我们注意到，除了return语句之外，没有任何声明表示该函数会返回一个值。调用这个函数的
            示例代码如下：
                var result = sum(10, 20);
                console.log(result); // 30

            这个函数会在执行完return语句之后停止并立即退出。因此，位于return语句之后的任何代码都永远不会执行。例如：
                function sum(num1, num2) {
                    return num1 + num2;
                    console.log("hello world"); // 这句到吗永远不会执行
                }

            return 语句也可以不带任何返回值。在这种情况下，函数停止执行后并返回undefined值。这种用法一般用在需要提前停止函数执行而又不需要返回值
            的情况下。

            推荐的做法是要么让函数始终都返回一个值，要么永远都不要返回值。否则，如果函数有时候返回值，有时候不返回值，会给调试代码带来不便。

            严格模式对函数有一些限制：
                * 不能把函数命名为eval或arguments
                * 不能把参数命名为eval或arguments
                * 不能出现两个命名参数重名的情况
            如果发生以上情况，就会导致语法错误，代码无法执行。
                
            理解参数：
                ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript函数不介意传递过来多少参数，也不在乎传递过来的参数是什么数据类型。
                也就是说，即便你定义的函数只接收两个参数，在调用这个函数时也未必一定要传两个参数。可以传一个、三个甚至不传参数，而解析器不会有什么怨言。
                之所以会这样，原因是ECMAScript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组，而不必关心数组中包含哪些参数（如果有参数的话）
                如果这个数组中不包含任何元素，无所谓；如果包含多个元素，也没有问题。实际上，在函数体内可以通过arguments对象来访问这个参数数组，从而获取
                传递给函数的每一个参数。

                其实arguments对象只是与数组类似（它并不是Array的实例），因为可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0]，第二个元素是arguments[1])
                使用length属性可以确定传递进来多少个参数。在前面的例子中，sayHi()函数的第一个参数名字为name，而该参数的值也可以通过arguments[0]来获得
                因此这个函数也可以改写成：
                    function sayHi() {
                        console.log("Hello " + arguments[0] + ", " + arguments[1]);
                    }

                这个重写后的函数中不包含命名的参数。虽然没有使用name和message标识符，但函数的功能依旧。这个事实说明了ECMAScript函数的一个重要特点：
                命名的参数只提供便利，但不是必须的。另外，在命名参数方面，其他语言可能需要事先创建一个函数签名，而将来的调用必须要与该签名一致。但在
                ECMAScript中，没有这些条条框框，解析器不会验证命名参数。

                通过访问arguments对象的length属性可以获知有多少个参数传递给了函数。arguments对象可以跟命名参数一起使用。它的值永远会与命名参数的值
                保持同步。如果函数只传入一个参数，那么arguments[1]得值得改变不会反映到命名参数中，这是因为arguments对象的长度是由传入参数的个数决定的
                而不是由定义函数时命名参数的个数决定的。
                
                没有传递值得命名参数将自动被赋予undefined值，这就跟定义了变量灭有被初始化一样。

                严格模式下使用arguments参数有一些限定，重写arguments的值会导致语法错误，代码不会执行。

                注意：ECMAScript中的参数都是值传递，不可能通过引用传递参数。

            

        */
    </script>
</body>
</html>